package database

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// QueryJob 查询任务
type QueryJob struct {
	ID      string
	Query   string
	Limit   int
	Timeout time.Duration
	Result  chan QueryResult
}

// QueryResult 查询结果
type QueryResult struct {
	ID     string
	Data   string
	Error  error
	Stats  QueryStats
}

// QueryStats 查询统计信息
type QueryStats struct {
	Duration    time.Duration `json:"duration"`
	RowsAffected int64        `json:"rows_affected"`
	StartTime   time.Time     `json:"start_time"`
	EndTime     time.Time     `json:"end_time"`
}

// ConcurrentExecutor 并发执行器
type ConcurrentExecutor struct {
	db          *DB
	workerCount int
	jobQueue    chan QueryJob
	wg          sync.WaitGroup
	ctx         context.Context
	cancel      context.CancelFunc
}

// NewConcurrentExecutor 创建新的并发执行器
func NewConcurrentExecutor(db *DB, workerCount int) *ConcurrentExecutor {
	ctx, cancel := context.WithCancel(context.Background())
	
	executor := &ConcurrentExecutor{
		db:          db,
		workerCount: workerCount,
		jobQueue:    make(chan QueryJob, workerCount*2), // 缓冲队列
		ctx:         ctx,
		cancel:      cancel,
	}

	// 启动工作协程
	executor.startWorkers()
	
	return executor
}

// startWorkers 启动工作协程
func (ce *ConcurrentExecutor) startWorkers() {
	for i := 0; i < ce.workerCount; i++ {
		ce.wg.Add(1)
		go ce.worker(i)
	}
}

// worker 工作协程
func (ce *ConcurrentExecutor) worker(id int) {
	defer ce.wg.Done()
	
	for {
		select {
		case job := <-ce.jobQueue:
			ce.processJob(job)
		case <-ce.ctx.Done():
			return
		}
	}
}

// processJob 处理查询任务
func (ce *ConcurrentExecutor) processJob(job QueryJob) {
	startTime := time.Now()
	
	// 创建任务特定的上下文
	jobCtx, cancel := context.WithTimeout(ce.ctx, job.Timeout)
	defer cancel()
	
	// 执行查询
	result, err := ce.db.ExecuteQueryWithTimeout(jobCtx, job.Query, job.Limit, job.Timeout)
	
	endTime := time.Now()
	
	// 构建查询结果
	queryResult := QueryResult{
		ID:    job.ID,
		Data:  result,
		Error: err,
		Stats: QueryStats{
			Duration:  endTime.Sub(startTime),
			StartTime: startTime,
			EndTime:   endTime,
		},
	}
	
	// 发送结果
	select {
	case job.Result <- queryResult:
	case <-ce.ctx.Done():
		return
	}
}

// SubmitQuery 提交查询任务
func (ce *ConcurrentExecutor) SubmitQuery(id, query string, limit int, timeout time.Duration) <-chan QueryResult {
	resultChan := make(chan QueryResult, 1)
	
	job := QueryJob{
		ID:      id,
		Query:   query,
		Limit:   limit,
		Timeout: timeout,
		Result:  resultChan,
	}
	
	select {
	case ce.jobQueue <- job:
		return resultChan
	case <-ce.ctx.Done():
		// 如果执行器已关闭，返回错误结果
		go func() {
			resultChan <- QueryResult{
				ID:    id,
				Error: fmt.Errorf("执行器已关闭"),
			}
		}()
		return resultChan
	}
}

// BatchExecute 批量执行查询
func (ce *ConcurrentExecutor) BatchExecute(queries []BatchQuery) []QueryResult {
	results := make([]QueryResult, len(queries))
	resultChans := make([]<-chan QueryResult, len(queries))
	
	// 提交所有查询
	for i, query := range queries {
		resultChans[i] = ce.SubmitQuery(
			fmt.Sprintf("batch_%d", i),
			query.Query,
			query.Limit,
			query.Timeout,
		)
	}
	
	// 收集所有结果
	for i, resultChan := range resultChans {
		select {
		case result := <-resultChan:
			results[i] = result
		case <-ce.ctx.Done():
			results[i] = QueryResult{
				ID:    fmt.Sprintf("batch_%d", i),
				Error: fmt.Errorf("执行器已关闭"),
			}
		}
	}
	
	return results
}

// BatchQuery 批量查询项
type BatchQuery struct {
	Query   string
	Limit   int
	Timeout time.Duration
}

// GetQueueSize 获取队列大小
func (ce *ConcurrentExecutor) GetQueueSize() int {
	return len(ce.jobQueue)
}

// GetWorkerCount 获取工作协程数量
func (ce *ConcurrentExecutor) GetWorkerCount() int {
	return ce.workerCount
}

// Close 关闭并发执行器
func (ce *ConcurrentExecutor) Close() {
	ce.cancel()
	ce.wg.Wait()
	close(ce.jobQueue)
}

// ExecutorStats 执行器统计信息
type ExecutorStats struct {
	WorkerCount int `json:"worker_count"`
	QueueSize   int `json:"queue_size"`
	IsRunning   bool `json:"is_running"`
}

// GetStats 获取执行器统计信息
func (ce *ConcurrentExecutor) GetStats() ExecutorStats {
	return ExecutorStats{
		WorkerCount: ce.workerCount,
		QueueSize:   len(ce.jobQueue),
		IsRunning:   ce.ctx.Err() == nil,
	}
}